package systems.database.query;

import java.util.LinkedList;

import systems.database.query.columns.ColumnItf;
import systems.database.query.columns.ColumnOrder;
import systems.database.query.condition.Condition;
import systems.database.query.exceptions.ColumnNotSelected;

/**
 * Provides a class to manage (C.R.U.D) a dummy select query.<br/>
 * A dummy select query could contain the following arguments :
 * <b>SELECT</b> [<b>DISTINCT</b> | <b>ALL</b>] <i>*</i> | <i>column lists</i>
 * <b>FROM</b> <i>name of the table</i> 
 * [<b>WHERE</b> <i>predicates</i>]
 * [<b>ORDER BY</b> > <i>column lists</i>]
 * @author Baptiste Legrand & Benjamin Orman
 */
public class SelectQuery implements Query{
	/* Distinct & All */
	private boolean distinct = false;
	private boolean all = false;
	/* Columns name */
	// If selectColumns is empty, then we will ask for all ( '*' ) the table columns
	private LinkedList<ColumnItf> selectColumns=new LinkedList<ColumnItf>();
	/* From tableName*/
	private String tableName="";
	/* Where */
	private Condition whereCondition;
	/* Order By*/
	private LinkedList<ColumnOrder> orderColumns=new LinkedList<ColumnOrder>();

	/**
	 * Empty constructor
	 */
	public SelectQuery()
	{}
	
	
	/**
	 * Function used to set the name of the table. 
	 * @param tableName - The table name
	 */
	public void setTableName(String tableName)
	{
		this.tableName = tableName;
	}
	
	/**
	 * 
	 */
	public void setWhereCondition(Condition condition)
	{
		this.whereCondition = condition;
	}
	
	
	public String getString()
	{
	  try{
	    return getQueryString();
	  }catch(Exception e){
	    return "";
	  }
	}
	/**
	 * @throws ColumnNotSelected 
	 * 
	 */
	private String getQueryString() throws ColumnNotSelected
	{
		String query="SELECT ";
		if(this.distinct && !this.all)
			query+=" DISTINCT ";
		else
			if(this.all && !this.distinct)
				query+=" ALL ";
		query+=buildSelectColumns();
		query+=" FROM ";
		query+=tableName;
		query+=buildWhere();
		query+=buildOrderBy();
		return query;
	}
	
	/**
	 * 
	 */
	private String buildSelectColumns()
	{
		int nbColumns = this.selectColumns.size();
		String selectColumns=" ";
		
		if(nbColumns>0)
			for(ColumnItf select: this.selectColumns)
				selectColumns+=select.getColumnName();
		else
			selectColumns=" * ";
		return selectColumns;
	}
	
	private String buildWhere()
	{
		String where=" WHERE ";
		if(this.whereCondition == null)
			return " ";
		where+=this.whereCondition.getConditionString();
		return where;
	}
	/**
	 * This must be the last part of the query.
	 */
	private String buildOrderBy() throws ColumnNotSelected
	{
		int colNb = orderColumns.size();
		int tmpColNb = 0;
		boolean check = true;
		String orderBy = " ORDER BY ";
		
		//If there is no order by constraint
		if(this.orderColumns.isEmpty())
			return " ";
		
		//If there is order by constraint ...
		//... Each ColumnItf for orderColumns must be declare in selectColumns
		// ... If there is no selectColumns, then all the columns are selected
		if(selectColumns.isEmpty())
			check = false;
		//... else we check if each orderColumns are define in the selectColumns
		for(ColumnOrder columnOrder : orderColumns)
		{
			ColumnItf tmpCol = columnOrder.getColumn();
			//... if we check if the columnOrder is set in the selectColumns 
			//and if it's not then we throws an Exception.
			if(check && !selectColumns.contains(tmpCol) )
				throw new ColumnNotSelected(tmpCol.getColumnName());
			//... else (the selectColumn contains the columnOrder or we don't have to check), we build the orberBy string
			orderBy += tmpCol.getColumnName()+" "+columnOrder.getOrder().toString();
			// if there is more columns to order, then we add a separator.
			if(tmpColNb < colNb)
				orderBy += " , ";
			tmpColNb ++;
		}
		return orderBy;
	}
	
/*	public static void main(String[] args) throws LiteralMalformedException, ColumnNotSelected
	{
		SelectQuery query = new SelectQuery();
		Literal level = new Literal("Level");
		Literal value = new Literal(10);
		
		Expression expression1 = new Expression(level);
		expression1.addComparatorAndLiteral(ComparatorEnum.LESS, value);

		Expression expression2 = new Expression(level);
		expression2.addComparatorAndLiteral(ComparatorEnum.GREATER, new Literal(2.20));
		
		
		Condition condition= new Condition(expression1);
		condition.addNextExpression(JunctionEnum.AND, expression2);
		
		query.setTableName("items");
		query.setWhereCondition(condition);
		
		System.out.println("Requete "+query.getQuery());
	}*/
}
